/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2015-10-29 11:45:55
 * Last Modified: 2015-10-29 15:26:45
 * File Name: mutex/mutextmanger.go
 * Description:
 */
package mutex

import (
	//"fmt"
	"sync"
)

//细粒度锁的管理
type MutexManager struct {
	mutexs map[string]*MutexItem
	lock   *sync.RWMutex
}

//锁对象基本单元
type MutexItem struct {
	Mutex  *sync.RWMutex
	RefNum int
	lock   *sync.RWMutex
}

func NewMutexManager() *MutexManager {
	return &MutexManager{
		mutexs: make(map[string]*MutexItem),
		lock:   new(sync.RWMutex),
	}
}

func NewMutexItem() *MutexItem {
	return &MutexItem{
		Mutex:  new(sync.RWMutex),
		RefNum: 0,
		lock:   new(sync.RWMutex),
	}
}

//对key对应的对象上锁
func (p *MutexManager) Lock(key string) {
	//fmt.Println("Lock for ", key)
	l := p.getRWMutex(key)
	//fmt.Println("get lock unit ok")
	l.Lock()
	//fmt.Println("Lock OK for ", key)
}

//对key对应的对象解锁
func (p *MutexManager) Unlock(key string) {
	//fmt.Println("UnLock for ", key)
	p.lock.Lock()
	defer p.lock.Unlock()
	item, ok := p.mutexs[key]
	if !ok {
		return
	}
	l := item.ReleaseRWMutex()
	l.Unlock()
	//fmt.Println("UnLock OK for ", key)
	if item.RefNum <= 0 {
		delete(p.mutexs, key)
	}
}

//根据key获取一把锁,如果不存在,则创建一个锁单元
func (p *MutexManager) getRWMutex(key string) *sync.RWMutex {
	p.lock.RLock()
	if item, ok := p.mutexs[key]; ok {
		p.lock.RUnlock()
		return item.GetRWMutex()
	}
	p.lock.RUnlock()

	p.lock.Lock()
	//fmt.Println("NewMutexItem")
	item := NewMutexItem()
	p.mutexs[key] = item
	p.lock.Unlock()
	return item.GetRWMutex()
}

//申请从锁单元中获取锁
func (p *MutexItem) GetRWMutex() *sync.RWMutex {
	p.lock.Lock()
	p.RefNum += 1
	p.lock.Unlock()
	return p.Mutex
}

//将锁单元中使用过的锁归还
func (p *MutexItem) ReleaseRWMutex() *sync.RWMutex {
	p.lock.Lock()
	p.RefNum -= 1
	p.lock.Unlock()
	return p.Mutex
}
